/**
 * Copyright (c) 2009 Mujtaba Hassanpur.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

import java.util.*;

/**
 * The Scoreboard class keeps track of a player's score.
 */
public class Scoreboard extends Observable
{
	private static Scoreboard board;
	private int score, sweeps, level;
	private long elapsedTime;
	private int speedModifier;
	
	// must be greater than or equal to the speed modifiers below
	private static final int SCORE_BASE = 2000;
	
	// used to increase game difficulty as player moves through the levels
	private static final int SWEEPS_PER_LEVEL = 20;
	private static final double SWEEP_MODIFIER = 0.85;
	
	/*
	 * Used in scoring. Also used to control speed of falling blocks,
	 * specifically how long (in ms) before a puzzle piece falls one slot down.
	 */
	private static final int SPEED_MODIFIER_EASY = 1500;
	private static final int SPEED_MODIFIER_NORMAL = 1000;
	private static final int SPEED_MODIFIER_HARD = 750;
	private static final int SPEED_MODIFIER_DEFAULT = SCORE_BASE;
	
	public static synchronized Scoreboard getScoreboard()
	{
		if(board == null)
		{
			board = new Scoreboard();
		}
		
		return board;
	}
	
	public Scoreboard()
	{
		score = 0;
		sweeps = 0;
		elapsedTime = 0;
		level = 1;
		
		//TODO change this based on difficulty level
		speedModifier = SPEED_MODIFIER_DEFAULT;
	}
	
	public int getSpeedModifier()
	{
		return speedModifier;
	}
	
	/**
	 * CollapsingBricksGame will call this when the game difficulty changes.
	 * @param newDifficulty The new difficulty of the game.
	 */
	public void updateSpeedModifier(CollapsingBricksGame.GameDifficulty newDifficulty)
	{
		switch(newDifficulty)
		{
			case EASY:
				speedModifier = SPEED_MODIFIER_EASY;
				break;
				
			case NORMAL:
				speedModifier = SPEED_MODIFIER_NORMAL;
				break;
				
			case HARD:
				speedModifier = SPEED_MODIFIER_HARD;
				break;
				
			default:
				speedModifier = SPEED_MODIFIER_DEFAULT;
				break;
		}
	}
	
	public void reset()
	{
		score = 0;
		sweeps = 0;
		elapsedTime = 0;
		updateSpeedModifier(CollapsingBricksGame.getCollapsingBricksGame().getGameDifficulty());
		notifyChanges();
	}
	
	public void notifyChanges()
	{
		setChanged();
		notifyObservers();
	}
	
	public int getScore()
	{
		return score;
	}
	
	public int getNumberOfSweeps()
	{
		return sweeps;
	}
	
	public long getElapsedTime()
	{
		return elapsedTime;
	}
	
	public int getLevel()
	{
		return level;
	}
	
	public void addPoints(int amount)
	{
		if((score + amount) >= 0)
			score += amount;
		else
			score = 0;
		
		notifyChanges();
	}
	
	public void updateElapsedTime(int amount)
	{
		if(amount > 0)
		{
			elapsedTime += amount;
			notifyChanges();
		}
	}
	
	public void incrementSweeps()
	{
		sweeps++;
		score += (SCORE_BASE - speedModifier);
		
		if(sweeps % SWEEPS_PER_LEVEL == 0)
		{
			level++;
			speedModifier = (int)(Math.round(speedModifier * SWEEP_MODIFIER));
		}
		notifyChanges();
		
		System.out.println(this);
	}
	
	public String toString()
	{
		String result = "Scoreboard:\n";
		result += "\tDifficulty: " + CollapsingBricksGame.getCollapsingBricksGame().getGameDifficulty() + "\n";
		result += "\tSweeps: " + sweeps + "\n";
		result += "\tScore: " + score + "\n";
		result += "\tLevel: " + level + "\n";
		result += "\tSpeedModifier: " + speedModifier + "\n";
		result += "\tElapsed Time: " + elapsedTime + "\n";
		return result;
	}
}
